#include <stdio.h>
#include <stdlib.h>
#include <rpc/pmap_clnt.h>
#include <string.h>
#include <memory.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include "dnfs.h"
#include "server.h"

#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif

static void
cs_2(struct svc_req *rqstp, register SVCXPRT *transp)
{
	union {
		struct lstat_in cs_lstat_2_arg;
		struct access_in cs_access_2_arg;
		struct opendir_in cs_opendir_2_arg;
		struct readdir_in cs_readdir_2_arg;
		struct readdir_in cs_closedir_2_arg;
		struct mknod_in cs_mknod_2_arg;
		struct open_in cs_open_2_arg;
		struct cs_newchunk_in cs_newchunk_2_arg;
		struct cs_release_in cs_release_2_arg;
		struct cs_unlink_in cs_unlink_2_arg;
		struct cs_truncate_in cs_truncate_2_arg;
		struct cs_update_permission_in cs_update_permission_2_arg;
		struct cs_rename_in cs_rename_2_arg;
		struct mkdir_in cs_mkdir_2_arg;
		struct rmdir_in cs_rmdir_2_arg;
	} argument;
	union {
		struct lstat_out cs_lstat_2_res;
		int cs_access_2_res;
		struct opendir_out cs_opendir_2_res;
		struct readdir_out cs_readdir_2_res;
		int cs_mknod_2_res;
		struct open_out cs_open_2_res;
		struct cs_newchunk_out cs_newchunk_2_res;
		int cs_release_2_res;
		int cs_unlink_2_res;
		int cs_truncate_2_res;
		int cs_update_permission_2_res;
		int cs_rename_2_res;
		int cs_mkdir_2_res;
		int cs_rmdir_2_res;
	} result;
	bool_t retval;
	xdrproc_t _xdr_argument, _xdr_result;
	bool_t (*local)(char *, void *, struct svc_req *);

	switch (rqstp->rq_proc) {
	case NULLPROC:
		(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
		return;

	case cs_lstat:
		_xdr_argument = (xdrproc_t) xdr_lstat_in;
		_xdr_result = (xdrproc_t) xdr_lstat_out;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_lstat_2_svc;
		break;

	case cs_access:
		_xdr_argument = (xdrproc_t) xdr_access_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_access_2_svc;
		break;

	case cs_opendir:
		_xdr_argument = (xdrproc_t) xdr_opendir_in;
		_xdr_result = (xdrproc_t) xdr_opendir_out;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_opendir_2_svc;
		break;

	case cs_readdir:
		_xdr_argument = (xdrproc_t) xdr_readdir_in;
		_xdr_result = (xdrproc_t) xdr_readdir_out;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_readdir_2_svc;
		break;

	case cs_closedir:
		_xdr_argument = (xdrproc_t) xdr_readdir_in;
		_xdr_result = (xdrproc_t) xdr_void;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_closedir_2_svc;
		break;

	case cs_mknod:
		_xdr_argument = (xdrproc_t) xdr_mknod_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_mknod_2_svc;
		break;

	case cs_open:
		_xdr_argument = (xdrproc_t) xdr_open_in;
		_xdr_result = (xdrproc_t) xdr_open_out;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_open_2_svc;
		break;

	case cs_newchunk:
		_xdr_argument = (xdrproc_t) xdr_cs_newchunk_in;
		_xdr_result = (xdrproc_t) xdr_cs_newchunk_out;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_newchunk_2_svc;
		break;

	case cs_release:
		_xdr_argument = (xdrproc_t) xdr_cs_release_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_release_2_svc;
		break;

	case cs_unlink:
		_xdr_argument = (xdrproc_t) xdr_cs_unlink_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_unlink_2_svc;
		break;

	case cs_truncate:
		_xdr_argument = (xdrproc_t) xdr_cs_truncate_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_truncate_2_svc;
		break;

	case cs_update_permission:
		_xdr_argument = (xdrproc_t) xdr_cs_update_permission_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_update_permission_2_svc;
		break;

	case cs_rename:
		_xdr_argument = (xdrproc_t) xdr_cs_rename_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_rename_2_svc;
		break;

	case cs_mkdir:
		_xdr_argument = (xdrproc_t) xdr_mkdir_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_mkdir_2_svc;
		break;

	case cs_rmdir:
		_xdr_argument = (xdrproc_t) xdr_rmdir_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))cs_rmdir_2_svc;
		break;

	default:
		svcerr_noproc (transp);
		return;
	}
	memset ((char *)&argument, 0, sizeof (argument));
	if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
		svcerr_decode (transp);
		return;
	}
	retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp);
	if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) {
		svcerr_systemerr (transp);
	}
	if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
		fprintf (stderr, "%s", "unable to free arguments");
		exit (1);
	}
	if (!cs_2_freeresult (transp, _xdr_result, (caddr_t) &result))
		fprintf (stderr, "%s", "unable to free results");

	return;
}

static void
os_2(struct svc_req *rqstp, register SVCXPRT *transp)
{
	union {
		struct os_loadreport_in os_loadreport_2_arg;
	} argument;
	union {
		int os_loadreport_2_res;
	} result;
	bool_t retval;
	xdrproc_t _xdr_argument, _xdr_result;
	bool_t (*local)(char *, void *, struct svc_req *);

	switch (rqstp->rq_proc) {
	case NULLPROC:
		(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
		return;

	case os_loadreport:
		_xdr_argument = (xdrproc_t) xdr_os_loadreport_in;
		_xdr_result = (xdrproc_t) xdr_int;
		local = (bool_t (*) (char *, void *,  struct svc_req *))os_loadreport_2_svc;
		break;

	default:
		svcerr_noproc (transp);
		return;
	}
	memset ((char *)&argument, 0, sizeof (argument));
	if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
		svcerr_decode (transp);
		return;
	}
	retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp);
	if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) {
		svcerr_systemerr (transp);
	}
	if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
		fprintf (stderr, "%s", "unable to free arguments");
		exit (1);
	}
	if (!os_2_freeresult (transp, _xdr_result, (caddr_t) &result))
		fprintf (stderr, "%s", "unable to free results");

	return;
}

int
main (int argc, char **argv)
{
	register SVCXPRT *transp;

	if (init() != 0){
		printf("init failed\n");
		return -1;
	}
	/*if (init_osd_list() != 0) {
		printf("init_osd_list failed\n");
		return -2;
	}*/
	pmap_unset (CS, CS_VERS);
	pmap_unset (OS, OS_VERS);
	transp = svcudp_create(RPC_ANYSOCK);
	if (transp == NULL) {
		fprintf (stderr, "%s", "cannot create udp service.");
		exit(1);
	}
	if (!svc_register(transp, CS, CS_VERS, cs_2, IPPROTO_UDP)) {
		fprintf (stderr, "%s", "unable to register (CS, CS_VERS, udp).");
		exit(1);
	}
	if (!svc_register(transp, OS, OS_VERS, os_2, IPPROTO_UDP)) {
		fprintf (stderr, "%s", "unable to register (OS, OS_VERS, udp).");
		exit(1);
	}
	transp = svctcp_create(RPC_ANYSOCK, 0, 0);
	if (transp == NULL) {
		fprintf (stderr, "%s", "cannot create tcp service.");
		exit(1);
	}
	if (!svc_register(transp, CS, CS_VERS, cs_2, IPPROTO_TCP)) {
		fprintf (stderr, "%s", "unable to register (CS, CS_VERS, tcp).");
		exit(1);
	}
	if (!svc_register(transp, OS, OS_VERS, os_2, IPPROTO_TCP)) {
		fprintf (stderr, "%s", "unable to register (OS, OS_VERS, tcp).");
		exit(1);
	}
	
	printf("After register to portmap\n");

	svc_run ();
	fprintf (stderr, "%s", "svc_run returned");
	exit (1);
	/* NOTREACHED */
}
